// src/main/java/org/example/backend/service/InternshipService.java
package org.example.backend.service;

import org.example.backend.dto.InternshipDetailDto;
import org.example.backend.dto.StudentInternshipInfoDto;
import org.example.backend.entity.*;
import org.example.backend.exception.BusinessException;
import org.example.backend.exception.ResourceNotFoundException;
import org.example.backend.repository.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
@Transactional
public class InternshipService {

    private final InternshipRepository internshipRepository;
    private final StudentRepository studentRepository;
    private final TeacherRepository teacherRepository;
    private final CompanyRepository companyRepository;
    private final UserRepository userRepository;
    private final InternshipPositionRepository internshipPositionRepository;
    private final InternshipApplicationRepository internshipApplicationRepository;

    public InternshipService(InternshipRepository internshipRepository,
                           StudentRepository studentRepository,
                           TeacherRepository teacherRepository,
                           CompanyRepository companyRepository,
                           UserRepository userRepository,
                           InternshipPositionRepository internshipPositionRepository,
                           InternshipApplicationRepository internshipApplicationRepository) {
        this.internshipRepository = internshipRepository;
        this.studentRepository = studentRepository;
        this.teacherRepository = teacherRepository;
        this.companyRepository = companyRepository;
        this.userRepository = userRepository;
        this.internshipPositionRepository = internshipPositionRepository;
        this.internshipApplicationRepository = internshipApplicationRepository;
    }

    /**
     * 创建实习记录（在申请通过时调用）
     */
    public Internship createInternship(InternshipApplication application) {
        Internship internship = new Internship();
        internship.setStudentId(application.getStudentId());
        internship.setCompanyId(application.getCompanyId());
        internship.setPositionId(application.getPositionId());
        internship.setApplicationId(application.getId());
        internship.setStatus(0); // 默认未开始状态

        return internshipRepository.save(internship);
    }

    /**
     * 获取实习详情
     */
    @Transactional(readOnly = true)
    public Internship getInternshipById(Long internshipId) {
        return internshipRepository.findById(internshipId)
                .orElseThrow(() -> new ResourceNotFoundException("实习记录不存在"));
    }

    /**
     * 根据学生ID获取实习信息
     */
    @Transactional(readOnly = true)
    public Internship getInternshipByStudentId(Long studentId) {
        return internshipRepository.findByStudentId(studentId)
                .orElseThrow(() -> new ResourceNotFoundException("实习记录不存在"));
    }

    /**
     * 获取实习详情（包含关联信息）
     */
    @Transactional(readOnly = true)
    public InternshipDetailDto getInternshipWithDetails(Long internshipId) {
        Internship internship = internshipRepository.findById(internshipId)
                .orElseThrow(() -> new ResourceNotFoundException("实习记录不存在"));

        InternshipDetailDto dto = new InternshipDetailDto();
        dto.setId(internship.getId());
        dto.setStudentId(internship.getStudentId());
        dto.setCompanyId(internship.getCompanyId());
        dto.setPositionId(internship.getPositionId());
        dto.setApplicationId(internship.getApplicationId());
        dto.setTeacherId(internship.getTeacherId());
        dto.setMentorName(internship.getMentorName());
        dto.setMentorPhone(internship.getMentorPhone());
        dto.setMentorEmail(internship.getMentorEmail());
        dto.setStatus(internship.getStatus());
        dto.setStartDate(internship.getStartDate());
        dto.setEndDate(internship.getEndDate());
        dto.setCreatedAt(internship.getCreatedAt());
        dto.setUpdatedAt(internship.getUpdatedAt());

        // 获取学生姓名
        try {
            Student student = studentRepository.findById(internship.getStudentId())
                    .orElse(null);
            if (student != null) {
                dto.setStudentName(student.getName());
            }
        } catch (Exception e) {
            // 忽略异常，保持字段为null
        }

        // 获取公司名称
        try {
            Company company = companyRepository.findById(internship.getCompanyId())
                    .orElse(null);
            if (company != null) {
                dto.setCompanyName(company.getName());
            }
        } catch (Exception e) {
            // 忽略异常，保持字段为null
        }

        // 获取岗位标题
        try {
            InternshipPosition position = internshipPositionRepository.findById(internship.getPositionId())
                    .orElse(null);
            if (position != null) {
                dto.setPositionTitle(position.getTitle());
            }
        } catch (Exception e) {
            // 忽略异常，保持字段为null
        }

        // 获取教师姓名
        try {
            if (internship.getTeacherId() != null) {
                Teacher teacher = teacherRepository.findById(internship.getTeacherId())
                        .orElse(null);
                if (teacher != null) {
                    dto.setTeacherName(teacher.getName());
                }
            }
        } catch (Exception e) {
            // 忽略异常，保持字段为null
        }

        return dto;
    }

    /**
     * 分配指导教师
     */
    public Internship assignTeacher(Long internshipId, Long teacherId, Long operatorId) {
        Internship internship = internshipRepository.findById(internshipId)
                .orElseThrow(() -> new ResourceNotFoundException("实习记录不存在"));

        // 检查教师是否存在
        Teacher teacher = teacherRepository.findById(teacherId)
                .orElseThrow(() -> new BusinessException("指定的教师不存在"));

        // 检查操作权限（教师只能分配自己或管理员分配）
        User operator = userRepository.findById(operatorId)
                .orElseThrow(() -> new BusinessException("操作用户不存在"));

        if (operator.getRole() == User.Role.TEACHER) {
            if (!teacherId.equals(operatorId)) {
                throw new BusinessException("教师只能为自己指导的实习分配自己");
            }
        }

        internship.setTeacherId(teacherId);
        return internshipRepository.save(internship);
    }

    /**
     * 更新企业导师信息
     */
    public Internship updateMentorInfo(Long internshipId, String mentorName, String mentorPhone, String mentorEmail, Long operatorId) {
        Internship internship = internshipRepository.findById(internshipId)
                .orElseThrow(() -> new ResourceNotFoundException("实习记录不存在"));

        // 检查操作权限（企业只能更新自己的实习或管理员操作）
        User operator = userRepository.findById(operatorId)
                .orElseThrow(() -> new BusinessException("操作用户不存在"));

        if (operator.getRole() == User.Role.COMPANY) {
            Company company = companyRepository.findByUserId(operatorId)
                    .orElseThrow(() -> new BusinessException("企业信息不存在"));
            if (!internship.getCompanyId().equals(company.getId())) {
                throw new BusinessException("无权限操作该实习");
            }
        }

        internship.setMentorName(mentorName);
        internship.setMentorPhone(mentorPhone);
        internship.setMentorEmail(mentorEmail);

        return internshipRepository.save(internship);
    }

    /**
     * 更新实习状态
     */
    public Internship updateInternshipStatus(Long internshipId, Integer status, Long operatorId) {
        Internship internship = internshipRepository.findById(internshipId)
                .orElseThrow(() -> new ResourceNotFoundException("实习记录不存在"));

        // 记录原状态
        Integer oldStatus = internship.getStatus();
        internship.setStatus(status);

        // 自动填充日期
        if (oldStatus != 1 && status == 1) {
            // 从未开始变为进行中时，设置开始日期
            internship.setStartDate(new Date());
        }

        if (oldStatus == 1 && (status == 2 || status == 3)) {
            // 从进行中变为完成或终止时，设置结束日期
            internship.setEndDate(new Date());
        }

        // 检查操作权限
        User operator = userRepository.findById(operatorId)
                .orElseThrow(() -> new BusinessException("操作用户不存在"));

        // 不同角色有不同的状态更新权限
        switch (operator.getRole()) {
            case STUDENT:
                // 学生只能将状态从未开始更新为进行中
                if (!(oldStatus == 0 && status == 1)) {
                    throw new BusinessException("学生无权限执行此操作");
                }
                break;
            case TEACHER:
                // 教师可以更新自己指导的实习状态
                Teacher teacher = teacherRepository.findByUserId(operatorId)
                        .orElseThrow(() -> new BusinessException("教师信息不存在"));
                if (internship.getTeacherId() == null || !internship.getTeacherId().equals(teacher.getId())) {
                    throw new BusinessException("无权限操作该实习");
                }
                break;
            case COMPANY:
                // 企业可以更新自己的实习状态
                Company company = companyRepository.findByUserId(operatorId)
                        .orElseThrow(() -> new BusinessException("企业信息不存在"));
                if (!internship.getCompanyId().equals(company.getId())) {
                    throw new BusinessException("无权限操作该实习");
                }
                break;
            case ADMIN:
                // 管理员可以更新所有实习状态
                break;
            default:
                throw new BusinessException("无权限执行此操作");
        }

        return internshipRepository.save(internship);
    }

    /**
     * 学生获取自己的实习列表
     */
    @Transactional(readOnly = true)
    public Page<Internship> getInternshipsByStudent(Long studentId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        return internshipRepository.findByStudentId(studentId, pageable);
    }

    /**
     * 学生获取自己的实习列表（包含关联信息）
     */
    @Transactional(readOnly = true)
    public Page<InternshipDetailDto> getInternshipsWithDetailsByStudent(Long studentId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        Page<Internship> internshipPage = internshipRepository.findByStudentId(studentId, pageable);

        return internshipPage.map(this::convertToDetailDto);
    }

    /**
     * 教师获取自己指导的实习列表
     */
    @Transactional(readOnly = true)
    public Page<Internship> getInternshipsByTeacher(Long teacherId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        return internshipRepository.findByTeacherId(teacherId, pageable);
    }

    /**
     * 教师获取自己指导的实习列表（包含关联信息）
     */
    @Transactional(readOnly = true)
    public Page<InternshipDetailDto> getInternshipsWithDetailsByTeacher(Long teacherId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        Page<Internship> internshipPage = internshipRepository.findByTeacherId(teacherId, pageable);

        return internshipPage.map(this::convertToDetailDto);
    }

    /**
     * 企业获取相关的实习列表
     */
    @Transactional(readOnly = true)
    public Page<Internship> getInternshipsByCompany(Long companyId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        return internshipRepository.findByCompanyId(companyId, pageable);
    }

    /**
     * 企业获取相关的实习列表（包含关联信息）
     */
    @Transactional(readOnly = true)
    public Page<InternshipDetailDto> getInternshipsWithDetailsByCompany(Long companyId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        Page<Internship> internshipPage = internshipRepository.findByCompanyId(companyId, pageable);

        return internshipPage.map(this::convertToDetailDto);
    }

    /**
     * 检查是否是企业的实习
     */
    @Transactional(readOnly = true)
    public boolean isCompanyInternship(Long internshipId, Long companyId) {
        return internshipRepository.existsByIdAndCompanyId(internshipId, companyId);
    }

    /**
     * 管理员获取所有实习列表
     */
    @Transactional(readOnly = true)
    public Page<Internship> getAllInternships(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        return internshipRepository.findAll(pageable);
    }

    /**
     * 管理员获取所有实习列表（包含关联信息）
     */
    @Transactional(readOnly = true)
    public Page<InternshipDetailDto> getAllInternshipsWithDetails(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        Page<Internship> internshipPage = internshipRepository.findAll(pageable);

        return internshipPage.map(this::convertToDetailDto);
    }

    /**
     * 根据申请ID获取实习记录
     */
    @Transactional(readOnly = true)
    public Internship getInternshipByApplicationId(Long applicationId) {
        return internshipRepository.findByApplicationId(applicationId)
                .orElseThrow(() -> new ResourceNotFoundException("实习记录不存在"));
    }

    /**
     * 通过学生ID获取实习信息（仅包含指定字段）
     */
    @Transactional(readOnly = true)
    public List<StudentInternshipInfoDto> getStudentInternshipInfo(Long studentId) {
        return internshipRepository.findInternshipInfoByStudentId(studentId);
    }
    /**
     * 获取教师所有相关的实习列表（已评定和未评定）
     */
    @Transactional(readOnly = true)
    public Page<InternshipDetailDto> getAllEvaluationsByTeacher(Long teacherId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));

        // 查询该教师指导的所有实习
        Page<Internship> internships = internshipRepository.findByTeacherId(teacherId, pageable);

        return internships.map(this::convertToDetailDto);
    }




    /**
     * 将 Internship 转换为 InternshipDetailDto
     */
    private InternshipDetailDto convertToDetailDto(Internship internship) {
        InternshipDetailDto dto = new InternshipDetailDto();
        dto.setId(internship.getId());
        dto.setStudentId(internship.getStudentId());
        dto.setCompanyId(internship.getCompanyId());
        dto.setPositionId(internship.getPositionId());
        dto.setApplicationId(internship.getApplicationId());
        dto.setTeacherId(internship.getTeacherId());
        dto.setMentorName(internship.getMentorName());
        dto.setMentorPhone(internship.getMentorPhone());
        dto.setMentorEmail(internship.getMentorEmail());
        dto.setStatus(internship.getStatus());
        dto.setStartDate(internship.getStartDate());
        dto.setEndDate(internship.getEndDate());
        dto.setCreatedAt(internship.getCreatedAt());
        dto.setUpdatedAt(internship.getUpdatedAt());

        // 获取学生姓名
        try {
            Student student = studentRepository.findById(internship.getStudentId())
                    .orElse(null);
            if (student != null) {
                dto.setStudentName(student.getName());
            }
        } catch (Exception e) {
            // 忽略异常
        }

        // 获取公司名称
        try {
            Company company = companyRepository.findById(internship.getCompanyId())
                    .orElse(null);
            if (company != null) {
                dto.setCompanyName(company.getName());
            }
        } catch (Exception e) {
            // 忽略异常
        }

        // 获取岗位标题
        try {
            InternshipPosition position = internshipPositionRepository.findById(internship.getPositionId())
                    .orElse(null);
            if (position != null) {
                dto.setPositionTitle(position.getTitle());
            }
        } catch (Exception e) {
            // 忽略异常
        }

        // 获取教师姓名
        try {
            if (internship.getTeacherId() != null) {
                Teacher teacher = teacherRepository.findById(internship.getTeacherId())
                        .orElse(null);
                if (teacher != null) {
                    dto.setTeacherName(teacher.getName());
                }
            }
        } catch (Exception e) {
            // 忽略异常
        }

        return dto;
    }
}
